package com.app.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.app.mapper.MySqlMapper;
import com.app.model.MysqlModel;
import com.app.service.MySqlService;
import com.app.util.CommonHelp;
import com.app.util.Constants;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
@Primary
public class MySqlServiceImpl extends ServiceImpl<MySqlMapper, MysqlModel> implements MySqlService {

    @Resource
    private MySqlMapper mySqlMapper;

    @Override
    public List<MysqlModel> selectBackupsList() {
        QueryWrapper<MysqlModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.select().ne("status",0).orderByDesc("create_time");
        List<MysqlModel> mysqlModelList = mySqlMapper.selectList(queryWrapper);
        return mysqlModelList;
    }

    @Override
    public Page<MysqlModel> getBackupsList(Integer page, Integer limit,String backupsName) {
       QueryWrapper<MysqlModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","database_name","size","backups_name","crt_time");
        if(backupsName != null){
            queryWrapper.like("backups_name",backupsName);
        }
        queryWrapper.orderByAsc("crt_time");
        Page<MysqlModel> pages = new Page<>();
        pages.setCurrent(page);
        pages.setSize(limit);
        Page<MysqlModel> roleList = mySqlMapper.selectPage(pages,queryWrapper);
        return roleList;
    }

    @Override
    public Object mysqlBackups(String filePath, String url, String userName, String password) {
        System.out.println("第一次打印"+url);
        // 获取ip
        final String ip = url.substring(13, 26);
        // 获取端口号
        final String port = url.substring(27, 31);
        // 获取数据库名称
        final String database_name = url.substring(32, 45);
        // 数据库文件名称
        StringBuilder mysqlFileName = new StringBuilder()
                .append(Constants.DATA_BASE_NAME)
                .append("_")
                .append(DateUtil.format(new Date(), "yyyy-MM-dd-HH-mm-ss"))
                .append(Constants.FILE_SUFFIX);
//        // 备份命令
//        StringBuilder cmd = new StringBuilder()
//                .append("mysqldump ")
//                .append("--no-tablespaces ")
//                .append("-h")
//                .append(ip)
//                .append(" -u")
//                .append(userName)
//                .append(" -p")
//                .append(password)
//                // 排除MySQL备份表
//                .append(" --ignore-table ")
//                .append(database_name)
//                .append(".mysql_backups ")
//                .append(database_name)
//                .append(" > ")
//                .append(filePath)
//                .append(mysqlFileName);
        // 备份命令
        StringBuilder cmd = new StringBuilder()
                .append("mysqldump ")
//                .append("--no-tablespaces ")
                .append("-h ")
                .append(ip)
                .append(" -u")
                .append(userName)
                .append(" -p")
                .append(password)
//                // 排除MySQL备份表
//                .append(" --ignore-table ")
//                .append(database_name)
//                .append(".mysql_backups ")
                .append(" "+database_name)
                .append(" > ")
                .append(filePath)
                .append(mysqlFileName);
        // 判断文件是否保存成功
        if (!FileUtil.exist(filePath)) {
            FileUtil.mkdir(filePath);
            return HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.value()+ "备份失败，文件保存异常，请查看文件内容后重新尝试！";
        }
        System.out.println("第6次打印"+cmd);
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        String[] command = new String[0];
        if (Constants.isSystem(osName)) {
            // Windows
            command = new String[]{"cmd", "/c",String.valueOf(cmd)};
        } else {
            // Linux
            command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
        }
        MysqlModel smb = new MysqlModel();
        // 备份信息存放到数据库
        smb.setMysqlIp(ip);
        smb.setMysqlPort(port);
        smb.setBackupsName(String.valueOf(mysqlFileName));
        smb.setDatabaseName(database_name);
        smb.setMysqlCmd(String.valueOf(cmd));
        smb.setSize("0");
        smb.setBackupsPath(filePath);
        smb.setCreateTime(CommonHelp.getNowTimestamp());
        smb.setStatus(1);
        smb.setOperation(0);
        mySqlMapper.insert(smb);
        // 获取Runtime实例
        try {
            Process process = Runtime.getRuntime().exec(command);
            if (process.waitFor() == 0) {
                File file = new File(filePath + mysqlFileName);
                MysqlModel smb1 = new MysqlModel();
                smb1.setSize(String.valueOf(file.length()));
                smb1.setId(smb.getId());
                mySqlMapper.updateById(smb1);
                log.error("数据库备份命令为：{}", cmd);
                log.error("Mysql 数据库备份成功,备份文件名：{}", mysqlFileName);
            } else {
                return HttpStatus.INTERNAL_SERVER_ERROR.value()+"网络异常，数据库备份失败";
            }
        } catch (Exception e) {
            e.printStackTrace();
            return HttpStatus.INTERNAL_SERVER_ERROR.value()+"网络异常，数据库备份失败";
        }
        return smb;
    }

    @Override
    public MysqlModel selectListId(Long id) {
        QueryWrapper<MysqlModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","mysql_ip","mysql_port","mysql_cmd","mysql_back_cmd","database_name","backups_path","size","backups_name","operation","status","recovery_time","crt_time").eq("id",id);
        MysqlModel model = mySqlMapper.selectOne(queryWrapper);
        return model;
    }

    @Override
    public void delete(int id) {
        mySqlMapper.deleteById(id);
    }

    @Override
    public Object rollback(MysqlModel smb, String userName, String password) {
        // 备份路径和文件名
        StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName());
        if (!FileUtil.exist(String.valueOf(realFilePath))) {
            return HttpStatus.NOT_FOUND.value()+ "文件不存在，恢复失败，请查看目录内文件是否存在后重新尝试！";
        }
        StringBuilder cmd = new StringBuilder()
                .append("mysql -h ")
                .append(smb.getMysqlIp())
                .append(" -u")
                .append(userName)
                .append(" -p")
                .append(password)
                .append(" ")
                .append(smb.getDatabaseName())
                .append(" < ")
                .append(realFilePath);
        String[] command = new String[0];
        log.error("数据库恢复命令为：{}", cmd);
        System.out.println("11111111"+cmd);
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        if (Constants.isSystem(osName)) {
            // Windows
            command = new String[]{"cmd", "/c", String.valueOf(cmd)};
        } else {
            // Linux
            command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
        }
        // 恢复指令写入到数据库
        smb.setMysqlBackCmd(String.valueOf(cmd));
        // 更新操作次数
        smb.setRecoveryTime(CommonHelp.getNowTimestamp());
        smb.setOperation(smb.getOperation() + 1);

        // 获取 Runtime 实例
//        Process process = null;
        try {
            Process process = Runtime.getRuntime().exec(command);
            process.waitFor();
            if (process.waitFor() == 0) {
                log.error("Mysql 数据库恢复成功, 恢复文件名：{}", realFilePath);
            } else {
                return HttpStatus.GATEWAY_TIMEOUT.value()+ "网络异常，恢复失败，请稍后重新尝试！";
            }
        } catch (Exception e) {
            e.printStackTrace();
            return HttpStatus.GATEWAY_TIMEOUT.value()+ "网络异常，恢复失败，请稍后重新尝试！";
        }
        return smb;
    }
}
